home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Tool Chest / Interapplication Communication / AE Tools / AEGizmos 1.4.2 / Sources / AEPrint.c < prev   
Encoding:
C/C++ Source or Header  |  1999-08-24  |  10.8 KB  |  474 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    AppleEvent Printer Function
  3.  *    by Jens Peter Alfke
  4.  *
  5.  *    Copyright ©1991-1993 Apple Computer, Inc. All rights reserved.
  6.  *
  7.  *    APPLE CONFIDENTIAL
  8.  */
  9.  
  10.  
  11. /*
  12.     CHANGE HISTORY:
  13.      ...zillions of changes from 2/91 until...
  14.      7/08/93    jpa        Allow for bufStr to be NULL, and return length, to support preflighting.
  15.                          Don't truncate hex dumps.
  16.      7/09/93    jpa        No, break length-counting into separate function (AEPrintLength).
  17.      9/29/93    jpa        Remove calls to vsprintf (cripping floating-point display, oh well...)
  18.     10/11/93    jpa        Display floats by coercing from 'sing' -> 'TEXT'.
  19.      4/14/94    jpa        Fix warnings for Metrowerks.
  20.      9/08/94    jpa        Added bufputOSType to fix quoting problems when re-parsing output.
  21.     10/03/94    jpa        Fixed heinous bug in printDescList that was always changing type to
  22.                         'aevt' on the way out.
  23.      3/20/95    jpa        **AEGizmos 1.4
  24. */
  25.  
  26.  
  27. #include <ctype.h>
  28. #include <stdarg.h>
  29. #include <Errors.h>
  30. #include <Packages.h>
  31. #include <AppleEvents.h>
  32. #include "AEPrint.h"
  33.  
  34.  
  35. typedef struct {
  36.     char *str;
  37.     long len;
  38. } Buf;
  39.  
  40.  
  41. static OSErr printDesc( Buf *buf, register AEDesc *desc );
  42.  
  43.  
  44. #ifdef THINK_C
  45. #if !__option(macsbug_names)
  46.     // Always turn on macsbug names for the non-static functions.
  47.     #define NO_NAMES
  48.     #pragma options(macsbug_names)
  49. #endif
  50. #endif
  51.  
  52.  
  53. /* AE_PRINT  The big kahuna. Print any AEDesc into bufStr, up to bufLen chars */
  54. OSErr
  55. AEPrint( AEDesc *desc, char *bufStr, long bufSize )
  56. {
  57.     Buf buf;
  58.     
  59.     if( !desc || !bufStr )
  60.         return paramErr;
  61.     buf.str = bufStr;
  62.     buf.len = bufSize -1;
  63.     bufStr[0] = '\0';
  64.     
  65.     return printDesc(&buf,desc);
  66. }
  67.  
  68.  
  69. /* AE_PRINT_SIZE  Compute the size of string (incl. null byte) AEPrint will build. */
  70. OSErr
  71. AEPrintSize( AEDesc *desc, long *stringLength )
  72. {
  73.     Buf buf;
  74.     OSErr err;
  75.     
  76.     if( !desc || !stringLength )
  77.         return paramErr;
  78.     buf.str = NULL;
  79.     buf.len = 0x7FFFFFF0;
  80.     
  81.     err= printDesc(&buf,desc);
  82.     
  83.     *stringLength = 0x7FFFFFF0 +1 - buf.len;        // Set to size of returned string (length+1)
  84.     return err;
  85. }
  86.  
  87.  
  88. #ifdef NO_NAMES
  89.     #undef NO_NAMES
  90.     #pragma options(!macsbug_names)
  91. #endif
  92.  
  93.  
  94. /*******************************  THE UTILITY BELT  ************************************/
  95.  
  96.  
  97. /* BUF_PUT  Copy data to the buffer */
  98. static void
  99. bufput( register Buf *buf, void *data, register long len )
  100. {
  101.     if( buf->len > 0 ) {
  102.         if( buf->len < len )
  103.             len = buf->len;
  104.         if( buf->str ) {                        // Only write data if we have a place for it
  105.             BlockMove(data,buf->str,len);
  106.             buf->str += len;
  107.             buf->str[0] = '\0';
  108.         }
  109.         buf->len -= len;
  110.     }
  111. }
  112.  
  113.  
  114. /* BUF_PUT_C  Copy a single char to the buffer */
  115. static void
  116. bufputc( register Buf *buf, char c )
  117. {
  118.     if( buf->len > 0 ) {
  119.         buf->len--;
  120.         if( buf->str ) {
  121.             *(buf->str)++ = c;
  122.             buf->str[0] = '\0';
  123.         }
  124.     }
  125. }
  126.  
  127.  
  128. /* BUF_PUT_S  Write a C string to the buffer */
  129. static void
  130. bufputs( Buf *buf, register char *str )
  131. {
  132.     register long len = buf->len;
  133.     register char *dst= buf->str;
  134.     
  135.     if( buf->str ) {
  136.         for(; *str && len>0; len-- )
  137.             *dst++ = *str++;
  138.         *dst = '\0';
  139.         buf->str = dst;
  140.     } else
  141.         for(; *str && len>0; len-- )            // No buffer, just count length of str
  142.             str++;
  143.     buf->len = len;
  144. }
  145.  
  146.  
  147. /* BUF_PUT_OSTYPE  Write a 4-character code to the buffer */
  148. static void
  149. bufputOSType( Buf *buf, OSType type )
  150. {
  151.     // If type contains any nonalphabetic chars, quote it.
  152.     // $$$$$ This still won't handle embedded single quotes.
  153.     short i;
  154.     unsigned char c;
  155.     Boolean space=false, alpha=false;
  156.     
  157.     for( i=0; i<4; i++ )
  158.         if( isalpha( c=((unsigned char*)&type)[i] ) ) {
  159.             if( space )
  160.                 break;                        // alpha after a space is bad
  161.             alpha = true;
  162.         } else if( c==' ' && alpha )
  163.             space = true;                    // space is ok after alpha chars
  164.         else
  165.             break;
  166.  
  167.     if( i<4 )
  168.         bufputc(buf,'\'');
  169.     bufput(buf,&type,sizeof(type));
  170.     if( i<4 )
  171.         bufputc(buf,'\'');
  172. }
  173.  
  174.  
  175. /* BUF_PUT_FLOAT  Write a floating-point number to a buffer */
  176. static OSErr
  177. bufputfloat( Buf *buf, float f )
  178. {
  179.     AEDesc desc, textDesc;
  180.     OSErr err;
  181.     
  182.     err= AECreateDesc(typeSMFloat,&f,sizeof(f), &desc);
  183.     if( err ) return err;
  184.     err= AECoerceDesc(&desc,'TEXT',&textDesc);
  185.     AEDisposeDesc(&desc);
  186.     if( !err ) {
  187.         bufput(buf,*textDesc.dataHandle,GetHandleSize(textDesc.dataHandle));
  188.         AEDisposeDesc(&textDesc);
  189.     }
  190.     return err;
  191. }
  192.  
  193.  
  194. /***************************  SUPPORT FOR PRINTING EVENTS  ********************************/
  195.  
  196.  
  197. static OSErr
  198. getOptionalParams( AppleEvent *event, AEKeyword** *keys )
  199. {
  200.     OSErr err;
  201.     AEDescList optionals;
  202.     long n, realSize;
  203.     AEKeyword key, optionalKey;
  204.     DescType type;
  205.     
  206.     *keys = NULL;
  207.     err= AEGetAttributeDesc( event, keyOptionalKeywordAttr,typeAEList, &optionals );
  208.     if( err )
  209.         if( err==errAEDescNotFound )
  210.             return noErr;
  211.         else
  212.             return err;
  213.     
  214.     err= AECountItems(&optionals, &n);
  215.     if( err ) goto exit;
  216.     if( n<=0 )
  217.         goto exit;
  218.     *keys = (void*) NewHandle(n*sizeof(AEKeyword));
  219.     if( (err= MemError()) != noErr ) goto exit;
  220.     
  221.     for( ; n>0; n-- ) {
  222.         err= AEGetNthPtr(&optionals,n,typeKeyword, &key,&type,
  223.                          (Ptr)&optionalKey,sizeof(optionalKey),&realSize);
  224.         if( err ) goto exit;
  225.         (**keys)[n-1] = optionalKey;
  226.     }
  227.  
  228. exit:
  229.     AEDisposeDesc(&optionals);
  230.     if( err && *keys ) {
  231.         DisposeHandle((Handle)*keys);
  232.         *keys = NULL;
  233.     }
  234.     return err;
  235. }
  236.  
  237.  
  238. static Boolean
  239. keyInList( AEKeyword key, AEKeyword **list )
  240. {
  241.     AEKeyword *elem;
  242.     long i;
  243.     
  244.     if( list==NULL )
  245.         return false;
  246.     for( elem= *list, i= GetHandleSize((Handle)list);  i>=0;  i-=sizeof(AEKeyword), elem++ )
  247.         if( key == *elem )
  248.             return true;
  249.     return false;
  250. }
  251.  
  252.  
  253. /*******************************  THE MAIN ROUTINES  ***********************************/
  254.  
  255.  
  256. /* PRINT_DESC_LIST  Print a descriptor list -- AEDescList, AERecord or AppleEvent */
  257. static OSErr
  258. printDescList( Buf *buf, AEDescList *desc, DescType originalType )
  259. {
  260.     DescType type = desc->descriptorType;
  261.     long i, size;
  262.     long itemNo = 0;
  263.     AEKeyword keyword;
  264.     AEDesc tempDesc;
  265.     short meta=false, doMeta=false;
  266.     AEKeyword **optionals = NULL;
  267.     OSErr err;
  268.     
  269.     if( type=='aevt' ) {
  270.         AEEventClass eventClass;
  271.         AEEventID eventID;
  272.         DescType realType;
  273.         long realSize;
  274.         
  275.         err= AEGetAttributePtr(    desc, keyEventClassAttr,typeType, &realType,
  276.                                 (Ptr)&eventClass, sizeof(eventClass), &realSize );
  277.         if( err ) goto exit;
  278.         bufputOSType(buf,eventClass);
  279.         
  280.         err= AEGetAttributePtr(    desc, keyEventIDAttr,typeType, &realType,
  281.                                 (Ptr)&eventID, sizeof(eventID), &realSize );
  282.         if( err ) goto exit;
  283.         bufputc(buf, '\\');
  284.         bufputOSType(buf,eventID);
  285.         
  286.         err= getOptionalParams(desc, &optionals);
  287.         if( err ) goto exit;
  288.         
  289.         doMeta = true;
  290.         
  291.         bufputc(buf, '{');
  292.         
  293.     } else if( type=='list' )
  294.         bufputc(buf, '[');                                /* Open-bracket for list */
  295.         
  296.     else {
  297.         if( originalType != 'reco' )
  298.             bufputOSType(buf, originalType);            /* Show type for coerced record */
  299.         bufputc(buf, '{');                                /* Open-brace for record */
  300.     }
  301.     
  302.     // Now get all the items and print them.
  303.     // If this is an Apple event, we will go around twice: one to print the parameters,
  304.     // and again to print the attributes.
  305.  
  306.     for( meta=false; meta<=doMeta; meta++) {
  307.         if( meta ) {
  308.             desc->descriptorType = 'meta';
  309.             if( optionals )
  310.                 DisposeHandle((Handle)optionals);
  311.             optionals = NULL;
  312.         }
  313.  
  314.         err= AECountItems(desc, &size);
  315.         if( err ) goto exit;
  316.         
  317.         for( i=1; i<=size; i++ ) {                            /* Loop through items: */
  318.             err= AEGetNthDesc(desc,i, typeWildCard, &keyword,&tempDesc);
  319.             if( err )
  320.                 goto exit;
  321.                 
  322.             if( meta && keyword=='optk' )                        // Skip optional-params attribute
  323.                 continue;
  324.                 
  325.             if( itemNo++ >0 )
  326.                 bufputs(buf, ", ");
  327.             if( meta )
  328.                 bufputc(buf,'&');                                // Prefix for metaparam (attribute)
  329.             else if( keyInList(keyword,optionals) )                // Prefix for optional parameter
  330.                 bufputc(buf,'~');
  331.             if( type!='list' ) {
  332.                 bufputOSType(buf,keyword);                        /* If we're in a record, show key */
  333.                 bufputc(buf,':');
  334.             }
  335.             err= printDesc(buf,&tempDesc);                        /* Recursively print item */
  336.             AEDisposeDesc(&tempDesc);
  337.             if( err ) goto exit;
  338.         }
  339.     }
  340.     
  341.     if( type=='list' )                    /* Close list or record */
  342.         bufputc(buf, ']');
  343.     else
  344.         bufputc(buf, '}');
  345.  
  346. exit:
  347.     if( optionals )
  348.         DisposeHandle((Handle)optionals);
  349.     if( doMeta )
  350.         desc->descriptorType = 'aevt';        // Fix it if we'd changed it to 'meta'
  351.     return err;
  352. }
  353.  
  354.  
  355. /* HEX_DUMP_DESC  Official punting routine. Produce hex dump of descriptor */
  356. static OSErr
  357. hexDumpDesc( Buf *buf, AEDesc *desc )
  358. {
  359.     unsigned char *data;
  360.     long count,n;
  361.     unsigned char byte;
  362.     char hex[] = "0123456789ABCDEF";
  363.     
  364.     bufputOSType(buf, desc->descriptorType);
  365.     bufputs(buf, "(«");
  366.     
  367.     data = (void*)*desc->dataHandle;
  368.     count = GetHandleSize(desc->dataHandle);
  369.  
  370.     n = count;
  371. #ifdef _MAX_HEX_DUMP_LENGTH_
  372.     if( n>_MAX_HEX_DUMP_LENGTH_ )
  373.         n = _MAX_HEX_DUMP_LENGTH_;
  374. #endif
  375.     if( n*2>buf->len )
  376.         n = buf->len>>1;                        // No sense going past end of buffer
  377.  
  378.     while( n-- >0 ) {
  379.         byte = *data++;
  380.         bufputc(buf,hex[byte>>4]);
  381.         bufputc(buf,hex[byte&0x0F]);
  382.     }
  383. #ifdef _MAX_HEX_DUMP_LENGTH_
  384.     if( count>_MAX_HEX_DUMP_LENGTH_ )
  385.         bufputc(buf,'…');
  386. #endif
  387.     bufputs(buf,"»)");
  388.     return noErr;
  389. }
  390.  
  391.  
  392. /*******************************  THE BIG KAHUNA  ************************************/
  393.  
  394.  
  395. /* PRINT_DESC  The big kahuna. Print any AEDesc */
  396. static OSErr
  397. printDesc( Buf *buf, register AEDesc *desc )
  398. {
  399.     OSErr err = noErr;
  400.     AEDesc tempDesc;
  401.     
  402.     if( desc->dataHandle==NULL || GetHandleSize(desc->dataHandle)==0 ) {
  403.         bufputc(buf,'\'');
  404.         bufputOSType(buf, desc->descriptorType);    /* No data */
  405.         bufputs(buf,"'()");
  406.         return noErr;
  407.     }
  408.     
  409.     switch( desc->descriptorType ) {
  410.         case 'bool':                                /* Integer types: */
  411.         case 'shor':
  412.         case 'long':
  413.             err= AECoerceDesc(desc,'long',&tempDesc);        /* Coerce to longint */
  414.             if( !err ) {
  415.                 unsigned char str[12];
  416.                 NumToString(**(long**)tempDesc.dataHandle,str);
  417.                 bufput(buf,str+1,str[0]);
  418.             } else if( err==errAECoercionFail )
  419.                 err= hexDumpDesc(buf,desc);
  420.             AEDisposeDesc(&tempDesc);
  421.             break;
  422.  
  423.         case 'sing':                                /* Floating-point types: */
  424.             bufputfloat(buf, **(float**)desc->dataHandle);
  425.             break;
  426.         case 'doub':
  427.             bufputfloat(buf, **(double**)desc->dataHandle);
  428.             break;
  429.         case 'exte':
  430.             bufputfloat(buf, **(long double**)desc->dataHandle);
  431.             break;
  432.  
  433.         case 'enum':                                /* 4-letter code: */
  434.             bufputOSType(buf, **(OSType**)desc->dataHandle);
  435.             break;
  436.  
  437.         case 'type':                                /* 4-letter code as 'type': */
  438.             bufputs(buf,"type(");
  439.             bufputOSType(buf, **(OSType**)desc->dataHandle);
  440.             bufputs(buf,")");
  441.             break;
  442.  
  443.         case 'TEXT':                                /* Text string: */
  444.             bufputc(buf,'“');
  445.             bufput(buf, *desc->dataHandle,GetHandleSize(desc->dataHandle));
  446.             bufputc(buf,'”');
  447.             break;
  448.  
  449.         case 'aevt':                                /* Apple event! */
  450.             err= printDescList(buf,desc,'aevt');
  451.             break;
  452.         
  453.         case 'list':                                /* AEDescList: */
  454.             err= printDescList(buf,desc,'list');
  455.             break;
  456.         
  457.         default:                                    /* AERecord, and everything else: */
  458.             if( desc->descriptorType=='reco' )
  459.                 tempDesc = *desc;
  460.             else
  461.                 err= AECoerceDesc(desc,'reco',&tempDesc);
  462.             
  463.             if( err==noErr ) {
  464.                 err= printDescList(buf,&tempDesc,        /* Made it a record, print it */
  465.                                     desc->descriptorType);
  466.                 if( desc->descriptorType != 'reco' )
  467.                     AEDisposeDesc(&tempDesc);
  468.             } else if( err==errAECoercionFail )            /* Couldn't make it a record */
  469.                 err= hexDumpDesc(buf,desc);
  470.             break;
  471.     }
  472.     return err;
  473. }
  474.